package com.tcm.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.OrderItem;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.tcm.common.enums.CachePrefix;
import com.tcm.entity.*;
import com.tcm.entity.bo.UserCacheBo;
import com.tcm.entity.dto.NotificationDto;
import com.tcm.entity.dto.param.NotificationPageParam;
import com.tcm.entity.vo.NotificationListResult;
import com.tcm.entity.resp.PageR;
import com.tcm.entity.vo.NotificationStuResult;
import com.tcm.exception.DatabaseOperationException;
import com.tcm.mapper.NotificationStudentMapper;
import com.tcm.service.*;
import com.tcm.mapper.NotificationMapper;
import com.tcm.utils.RedisUtil;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

/**
* @author Guqier
* @description 针对表【ts_notification(通知、公告)】的数据库操作Service实现
* @createDate 2023-07-28 16:49:10
*/
@Service
public class NotificationServiceImpl extends ServiceImpl<NotificationMapper, Notification> implements NotificationService{

    @Autowired
    private NotificationStudentMapper notificationStudentMapper;

    @Autowired
    private StudentService studentService;

    @Autowired
    private ClazzService clazzService;

    @Autowired
    private SocialClazzService socialClazzService;

    @Autowired
    private SocialStudentService socialStudentService;

    @Autowired
    private RedisUtil redisUtil;

    /**
     * 添加通知
     * @param dto 通知数据封装类
     * @param currUserId 当前登录用户ID
     * @return 处理结果，true为成功
     */
    @Override
    @Transactional
    public boolean addNotification(NotificationDto dto, Long currUserId) throws DatabaseOperationException{
        // 校验班级ID列表是否为空
        List<Long> clazzIds = dto.getClazzIds();
        if (CollectionUtils.isEmpty(clazzIds)) {
            return false;// 班级ID为空
        }
        // 构造通知实体类
        Notification notification = new Notification();
        BeanUtils.copyProperties(dto, notification, "clazzIds");
        notification.setClazzType(dto.getClazzType());
        notification.setClazzIds(clazzIds.stream().map(Object::toString).collect(Collectors.joining("|")));
        notification.setCreateUser(currUserId);
        notification.setUpdateUser(currUserId);
        boolean bn = this.save(notification);

        // 添加通知学生关系
        if (dto.getClazzType().equals(0)){// 普通班级
            // 获取所有学生
            List<Student> students = studentService.list();
            // 过滤属于班级ID指定班级的学生，并获取学生ID
            List<Student> studentList = students.stream().filter(student -> clazzIds.contains(student.getClazzId())).collect(Collectors.toList());
            int cnt = 0;// 计数器
            for (Student student : studentList) {
                NotificationStudent notificationStudent = new NotificationStudent();
                notificationStudent.setNotificationId(notification.getId());
                notificationStudent.setAccount(student.getAccount());
                notificationStudent.setIsRead(0);
                notificationStudent.setCreateUser(currUserId);
                notificationStudent.setUpdateUser(currUserId);
                if (notificationStudentMapper.insert(notificationStudent) == 1) {
                    cnt ++;
                }
            }
            if (cnt != studentList.size()){
                throw new DatabaseOperationException("通知学生关系保存失败");
            }
        }else {// 社会化班级
            List<SocialStudent> socialStudents = socialStudentService.list();
            List<SocialStudent> collect = socialStudents.stream().filter(socialStudent -> clazzIds.contains(socialStudent.getClazzId())).collect(Collectors.toList());
            int cnt = 0;// 计数器
            for (SocialStudent socialStudent : collect) {
                NotificationStudent notificationStudent = new NotificationStudent();
                notificationStudent.setNotificationId(notification.getId());
                notificationStudent.setAccount(socialStudent.getAccount());
                notificationStudent.setIsRead(0);
                notificationStudent.setCreateUser(currUserId);
                notificationStudent.setUpdateUser(currUserId);
                if (notificationStudentMapper.insert(notificationStudent) == 1) {
                    cnt ++;
                }
            }
            if (cnt != collect.size()){
                throw new DatabaseOperationException("通知社会化学员关系保存失败");
            }
        }

        if (!bn){
            throw new DatabaseOperationException("数据库操作失败");
        }
        return true;
    }


    /**
     * 删除通知
     * @param id 通知ID
     * @param currUserId 当前登录用户ID
     * @return 处理结果，true为成功
     * @throws DatabaseOperationException 数据库操作异常
     */
    @Override
    @Transactional
    public boolean removeNotification(Long id, Long currUserId) throws DatabaseOperationException{
        // 校验通知是否存在
        Notification notification = this.getById(id);
        if (notification == null) {
            return false;
        }
        // 删除通知
        boolean br = this.removeById(id);
        // 删除通知学生关系
        LambdaQueryWrapper<NotificationStudent> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(NotificationStudent::getNotificationId, id);
        Integer count = notificationStudentMapper.selectCount(queryWrapper);
        int delete = notificationStudentMapper.delete(queryWrapper);
        if (!br || count != delete){
            throw new DatabaseOperationException("数据库操作失败");
        }
        return true;
    }

    /**
     * 分页获取通知列表
     * @param param 通知参数封装
     * @return 通知列表
     */
    @Override
    public PageR<NotificationListResult> getNotificationListByPage(NotificationPageParam param){
        // 构造条件
        Page<Notification> page = new Page<>(param.getPage(), param.getPageSize());
        page.addOrder(OrderItem.desc("update_time"));
        LambdaQueryWrapper<Notification> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(param.getType() != null, Notification::getType, param.getType());
        queryWrapper.like(StringUtils.hasText(param.getTitle()), Notification::getTitle, param.getTitle());
        queryWrapper.like(StringUtils.hasText(param.getContent()), Notification::getContent, param.getContent());
        // 查询结果
        this.page(page, queryWrapper);


        // 准备数据
        List<Clazz> clazzList = clazzService.list();
        List<SocialClazz> socialClazzList = socialClazzService.list();
        // 构造结果集
        PageR<NotificationListResult> pageR = new PageR<>();
        BeanUtils.copyProperties(page, pageR, "records");
        pageR.setRecords(page.getRecords().stream().map(notification -> {
            NotificationListResult result = new NotificationListResult();
            BeanUtils.copyProperties(notification, result);
            if (!StringUtils.hasText(notification.getClazzIds())){
                result.setClazzNames(new ArrayList<>());
                return result;
            }
            List<String> clazzIds = Arrays.asList(notification.getClazzIds().split("\\|"));
            if (notification.getClazzType().equals(0)){
                // 普通班级
                result.setClazzNames(clazzList.stream().filter(clazz -> clazzIds.contains(clazz.getId().toString())).map(Clazz::getName).collect(Collectors.toList()));
            }else {
                // 社会化班级
                result.setClazzNames(socialClazzList.stream().filter(socialClazz -> clazzIds.contains(socialClazz.getId().toString())).map(SocialClazz::getName).collect(Collectors.toList()));
            }
            return result;
        }).collect(Collectors.toList()));
        return pageR;
    }

    /**
     * 学生获取通知列表
     * @param current 当前页号
     * @param pageSize 页面大小
     * @param currUserId 当前登录用户ID
     * @return 通知列表
     */
    @Override
    public PageR<NotificationStuResult> getStuNotifications(Integer current, Integer pageSize, Long currUserId){
        // 获取学生信息
        UserCacheBo userCacheBo = redisUtil.getCacheObject(CachePrefix.PC_USER_TOKEN.getCacheKey(currUserId.toString()));
        // 构造查询条件
        Page<NotificationStudent> page = new Page<>(current, pageSize);
        page.addOrder(OrderItem.asc("is_read"), OrderItem.desc("create_time"));
        LambdaQueryWrapper<NotificationStudent> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(NotificationStudent::getAccount, userCacheBo.getAccount());
        // 查询通知学生关系
        notificationStudentMapper.selectPage(page, queryWrapper);
        // 构造结果集
        PageR<NotificationStuResult> pageR = new PageR<>();
        BeanUtils.copyProperties(page, pageR, "records");
        List<NotificationStudent> notificationStudents = page.getRecords();
        if (CollectionUtils.isEmpty(notificationStudents)) {
            pageR.setRecords(new ArrayList<>());
            return pageR;
        }else {
            List<Notification> notifications = this.listByIds(notificationStudents.stream().map(NotificationStudent::getNotificationId).collect(Collectors.toList()));
            pageR.setRecords(notificationStudents.stream().map(notificationStudent -> {
                NotificationStuResult notificationStuResult = new NotificationStuResult();
                notifications
                        .stream()
                        .filter(notification -> notification.getId().equals(notificationStudent.getNotificationId()))
                        .findFirst()
                        .ifPresent(notification -> {
                            BeanUtils.copyProperties(notification, notificationStuResult);
                            notificationStuResult.setTime(notification.getCreateTime());
                        });
                notificationStuResult.setIsRead(notificationStudent.getIsRead());
                return notificationStuResult;
            }).collect(Collectors.toList()));
            return pageR;
        }
    }

    /**
     * 学生获取最新滚动通知
     * @param currUserId 当前用户ID
     * @return 最新滚动通知
     */
    @Override
    public NotificationStuResult getStuRollNotification(Long currUserId){
        // 获取学生信息
        UserCacheBo userCacheBo = redisUtil.getCacheObject(CachePrefix.PC_USER_TOKEN.getCacheKey(currUserId.toString()));
        // 查询最新滚动通知
        Notification rollNotification = this.getBaseMapper().getRollNotification(userCacheBo.getAccount());
        if (rollNotification == null) {
            return null;
        }
        // 构造结果
        NotificationStuResult result = new NotificationStuResult();
        BeanUtils.copyProperties(rollNotification, result);
        result.setTime(rollNotification.getCreateTime());
        return result;
    }

    /**
     * 已读通知
     * @param id 通知ID
     * @param currUserId 当前登录用户ID
     * @return 处理结果，true为成功，false为数据库操作失败
     */
    @Override
    public boolean readNotification(Long id, Long currUserId){
        // 获取学生信息
        UserCacheBo userCacheBo = redisUtil.getCacheObject(CachePrefix.PC_USER_TOKEN.getCacheKey(currUserId.toString()));
        // 获取通知学生关系
        NotificationStudent notificationStudent = notificationStudentMapper.selectOne(new LambdaQueryWrapper<NotificationStudent>().eq(NotificationStudent::getNotificationId, id).eq(NotificationStudent::getAccount, userCacheBo.getAccount()));
        notificationStudent.setIsRead(1);
        notificationStudent.setUpdateUser(currUserId);
        return notificationStudentMapper.updateById(notificationStudent) == 1;
    }

    @Override
    @Transactional
    public boolean addNotificationForStudent(String title, String content, Integer type, Integer isRoll, String account, Long currUserId){
        Notification notification = new Notification();
        notification.setTitle(title);
        notification.setContent(content);
        notification.setType(type);
        notification.setIsRoll(isRoll);
        notification.setClazzType(-1);
        notification.setCreateUser(currUserId);
        notification.setUpdateUser(currUserId);
        if (!this.save(notification)) {
            throw new DatabaseOperationException("添加通知失败");
        }

        NotificationStudent notificationStudent = new NotificationStudent();
        notificationStudent.setNotificationId(notification.getId());
        notificationStudent.setAccount(account);
        notificationStudent.setIsRead(0);
        notificationStudent.setCreateUser(currUserId);
        notificationStudent.setUpdateUser(currUserId);
        if (notificationStudentMapper.insert(notificationStudent) != 1) {
            throw new DatabaseOperationException("添加通知学生关系失败");
        }
        return true;
    }

}




